package com.ruoyi.video.service.impl;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.video.domain.Video;
import com.ruoyi.video.domain.VideoFile;
import com.ruoyi.video.domain.VideoHistory;
import com.ruoyi.video.domain.VideoRelation;
import com.ruoyi.video.mapper.VideoFileMapper;
import com.ruoyi.video.service.IVideoFileService;
import com.ruoyi.video.service.IVideoHistoryService;
import com.ruoyi.video.service.IVideoRelationService;
import com.ruoyi.video.service.IVideoService;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * 番剧文件Service业务层处理
 *
 * @author ruoyi
 * @date 2022-02-04
 */
@Service
public class VideoFileServiceImpl implements IVideoFileService {
    @Autowired
    private VideoFileMapper videoFileMapper;
    @Autowired
    private IVideoService videoService;
    @Autowired
    private IVideoHistoryService videoHistoryService;
    @Autowired
    private IVideoRelationService videoRelationService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 查询番剧文件
     *
     * @param id 番剧文件主键
     * @return 番剧文件
     */
    @Override
    public VideoFile selectVideoFileById(String id) {
        return videoFileMapper.selectVideoFileById(id);
    }

    /**
     * 查询番剧文件列表
     *
     * @param videoFile 番剧文件
     * @return 番剧文件
     */
    @Override
    public List<VideoFile> selectVideoFileList(VideoFile videoFile) {
        return videoFileMapper.selectVideoFileList(videoFile);
    }

    /**
     * 新增番剧文件
     *
     * @param videoFile 番剧文件
     * @return 结果
     */
    @Override
    public int insertVideoFile(VideoFile videoFile) {
        return videoFileMapper.insertVideoFile(videoFile);
    }

    /**
     * 修改番剧文件
     *
     * @param videoFile 番剧文件
     * @return 结果
     */
    @Override
    public int updateVideoFile(VideoFile videoFile) {
        return videoFileMapper.updateVideoFile(videoFile);
    }

    /**
     * 批量删除番剧文件
     *
     * @param ids 需要删除的番剧文件主键
     * @return 结果
     */
    @Override
    public int deleteVideoFileByIds(String[] ids) {
        return videoFileMapper.deleteVideoFileByIds(ids);
    }

    /**
     * 删除番剧文件信息
     *
     * @param id 番剧文件主键
     * @return 结果
     */
    @Override
    public int deleteVideoFileById(String id) {
        return videoFileMapper.deleteVideoFileById(id);
    }

    @Override
    public int batchSave(List<VideoFile> videoFile) {
        return videoFileMapper.batchSave(videoFile);
    }

    @Override
    public boolean moveFile(List<VideoFile> videoFiles) {
        if (CollectionUtils.isEmpty(videoFiles)) return false;
        Video video = videoService.selectVideoById(videoFiles.get(0).getVideoId());
        for (VideoFile videoFile : videoFiles) {
            String videoTemporary = FileUtils.splicingFilePath(RuoYiConfig.getVideoPath(), "videoTemporary", videoFile.getFilePath().replace(Constants.RESOURCE_PREFIX, ""));
            File oldFile = new File(videoTemporary);
            if (!oldFile.exists()) {
                continue;
            }
            File newFile = new File(FileUtils.splicingFilePath(RuoYiConfig.getVideoPath(), video.getName(), videoFile.getFileName()));
            File parentFile = newFile.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }
            boolean b = oldFile.renameTo(newFile);
            if (b) {
                videoFile.setFilePath(FileUtils.toWebPath(newFile.getAbsolutePath()));
            } else {
                logger.error("移动文件失败");
                System.out.println("移动文件失败");
            }
        }
        return false;
    }

    @Override
    public void getVideo(String videoId, HttpServletRequest request, HttpServletResponse response) {
        //视频资源存储信息
        VideoFile videoFile = videoFileMapper.selectVideoFileById(videoId);
        if (Objects.isNull(videoFile)) {
            respFileError(request, response, videoId);
        } else {
            fileToResp(request, response, videoFile.getFilePath(), videoFile.getExtendedName(), videoFile.getFileName());
        }
    }

    @Override
    public HashMap<String, Object> getVideoAllInfo(VideoFile videoFile_) {
        String id = videoFile_.getId();
        String videoId = videoFile_.getVideoId();
        if (StringUtils.isEmpty(videoId) && StringUtils.isEmpty(id)) return null;
        HashMap<String, Object> map = new HashMap<>();
        if (StringUtils.isNotEmpty(id)) {
            VideoFile videoFile = videoFileMapper.selectVideoFileById(id);
            if (Objects.isNull(videoFile)) return null;
            videoId = videoFile.getVideoId();
            map.put("videoFile", videoFile);
        }
        VideoFile videoFile = new VideoFile();
        videoFile.setVideoId(videoId);
        List<VideoFile> videoFiles = selectVideoFileList(videoFile);
        map.put("videoList", videoFiles);
        VideoHistory videoHistory = videoHistoryService.selectVideoHistoryByVideoId(videoId);
        map.put("videoHistory", videoHistory);
        map.put("videoRelation", new byte[]{});
        VideoRelation videoRelation = new VideoRelation();
        videoRelation.setVideoIds(videoId);
        List<VideoRelation> videoRelations = videoRelationService.selectVideoRelationList(videoRelation);
        if (CollectionUtils.isNotEmpty(videoRelations)) {
            String[] videoIds = videoRelations.get(0).getVideoIds().replaceAll(videoId + ",", "").split(",");
            List<Video> videos = videoService.selectVideoByIds(videoIds);
            map.put("videoRelation", videos);
        }
        //只有当前台没传指定的视频时才根据历史播放或播第一个视频
        if (Objects.isNull(map.get("videoFile"))) {
            if (Objects.nonNull(videoHistory)) {
                map.put("videoFile", videoFileMapper.selectVideoFileById(videoHistory.getVideoFileId()));
            } else if (CollectionUtils.isNotEmpty(videoFiles)) {
                map.put("videoFile", videoFiles.get(0));
            }
        }
        return map;
    }

    @Override
    public void getSubtitle(String videoId, HttpServletRequest request, HttpServletResponse response) {
        //字幕资源存储信息
        VideoFile videoFile = videoFileMapper.selectVideoFileById(videoId);
        if (Objects.isNull(videoFile)) {
            respFileError(request, response, videoId);
        } else {
            fileToResp(request, response, videoFile.getSubtitlePath(), videoFile.getSubtitleExtendedName(), videoFile.getSubtitleName());
//            FileReader fileReader = null;
//            try {
//                fileReader = new FileReader(videoFile.getSubtitlePath());
//                BufferedReader reader = new BufferedReader(fileReader);
//                StringBuilder sb = new StringBuilder();
//                String s;
//                while ((s = reader.readLine()) != null) sb.append(s);
//                String s1 = sb.toString();
//                if (s1.contains("�")) {
//                    s1 = new String(s1.getBytes(StandardCharsets.UTF_8), "GB2312");
//                }
//                System.out.println(s1);
//            } catch (FileNotFoundException e) {
//                throw new RuntimeException(e);
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            }
        }
    }

    /**
     * 根据文件路径将文件流输出给浏览器
     *
     * @param request  req
     * @param response resp
     * @param filePath 文件路径
     * @param mime     MIME类型
     * @param fileName 输出给浏览器的文件名
     */
    public void fileToResp(HttpServletRequest request, HttpServletResponse response, String filePath, String mime, String fileName) {
        response.reset();
        //获取从那个字节开始读取文件
        String rangeString = request.getHeader("Range");
        try {
            //获取响应的输出流
            OutputStream outputStream = response.getOutputStream();
            File file = new File(filePath);
            if (file.exists()) {
                RandomAccessFile targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                //播放
                if (rangeString != null) {
                    long range = Long.parseLong(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
                    //设置内容类型
                    response.setHeader("Content-Type", mime);
                    //设置此次相应返回的数据长度
                    response.setHeader("Content-Length", String.valueOf(fileLength - range));
                    //设置此次相应返回的数据范围
                    response.setHeader("Content-Range", "bytes " + range + "-" + (fileLength - 1) + "/" + fileLength);
                    //返回码需要为206，而不是200
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设定文件读取开始位置（以字节为单位）
                    targetFile.seek(range);
                } else {//下载
                    //设置响应头，把文件名字设置好
                    response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
                    //设置文件长度
                    response.setHeader("Content-Length", String.valueOf(fileLength));
                    //解决编码问题
                    response.setHeader("Content-Type", "application/octet-stream");
                }
                byte[] cache = new byte[1024 * 300];
                int flag;
                while ((flag = targetFile.read(cache)) != -1) {
                    outputStream.write(cache, 0, flag);
                }
            } else {
                String message = "file:" + fileName + " not exists";
                //解决编码问题
                response.setHeader("Content-Type", "application/json");
                outputStream.write(message.getBytes(StandardCharsets.UTF_8));
            }
            outputStream.flush();
            outputStream.close();
        } catch (ClientAbortException e) {
            logger.debug("你的主机中的软件中止了一个已建立的连接");
        } catch (FileNotFoundException e) {
            logger.error("输出文件时找不到文件", e);
        } catch (IOException e) {
            logger.error("输出文件时出错", e);
        }
    }

    public void respFileError(HttpServletRequest request, HttpServletResponse response, String fileName) {
        response.reset();
        //获取从那个字节开始读取文件
        String rangeString = request.getHeader("Range");
        try {
            //获取响应的输出流
            OutputStream outputStream = response.getOutputStream();

            String message = "file:" + fileName + " not exists";
            //解决编码问题
            response.setHeader("Content-Type", "application/json");
            outputStream.write(message.getBytes(StandardCharsets.UTF_8));

            outputStream.flush();
            outputStream.close();
        } catch (FileNotFoundException e) {
            logger.error("输出文件时找不到文件", e);
        } catch (IOException e) {
            logger.error("输出文件时出错", e);
        }
    }
}
